package org.example.gobang.api;


import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.gobang.game.MatchRequest;
import org.example.gobang.game.MatchResponse;
import org.example.gobang.game.Matcher;
import org.example.gobang.game.OnlineUserManager;
import org.example.gobang.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component
// 通过这个类来处理匹配功能中的websocket请求
public class MatchAPI extends TextWebSocketHandler {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private Matcher matcher;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //玩家上线 就要加入到OnlineUserManager类中

        //    1.先获取到当前用户的身份信息（谁在游戏大厅中）
        //    此处的代码, 之所以能够 getAttributes, 全靠了在注册 Websocket 的时候,
        //    加上的 .addInterceptors(new HttpSessionHandshakeInterceptor());
        //    这个逻辑就把 HttpSession 中的 Attribute 都给拿到 WebSocketSession 中了
        //    在 Http 登录逻辑中, 往 HttpSession 中存了 User 数据: httpSession.setAttribute("user", user);
        //    此时就可以在 WebSocketSession 中把之前 HttpSession 里存的 User 对象给拿到了.
        //    注意，此处的user可能是null的，如果用户没有通过http来进行登录
        //    而是直接通过/game_hall.html这个url来访问游戏大厅
        //    此时就会出现user为null的情况
        try {
            User user = (User) session.getAttributes().get("user");

            //2.先判断当前用户是否已经登陆过了（已经是在线状态） 如果是已经登陆过了，就不执行后续的逻辑
            //判断用户是否多开
            //WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId());
            //if (tmpSession != null)
             if (onlineUserManager.getFromGameHall(user.getUserId()) != null
                                || onlineUserManager.getFromGameRoom(user.getUserId()) != null) {
                //说明此时用户已经在线
                //针对这个情况要告诉客户端，你这里重复登陆了。
                MatchResponse response = new MatchResponse();
                response.setOk(true);
                response.setReason("禁止用户多开！");
                response.setMessage("repeatConnection");
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                // 此处直接关闭有些太激进了, 还是返回一个特殊的 message , 供客户端来进行判定, 由客户端负责进行处理
                //session.close();
                return;
            }

            //3..拿到了身份信息之后, 就可以把玩家设置成在线状态了
            onlineUserManager.enterGameHall(user.getUserId(), session);
            System.out.println("玩家 " + user.getUsername() + " 进入游戏大厅");
        }catch (NullPointerException e){
            System.out.println("[MatchAPI.afterConnectionEstablished] 当前用户未登录!");
            //e.printStackTrace();
            //出现空指针异常，说明当前用户的身份信息是空的，用户未登录
            //需要把用户未登陆的信息给返回回去
            MatchResponse response = new MatchResponse();
            response.setOk(false);
            response.setReason("您尚未登录，不能进行后续匹配功能！");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        // 实现处理开始匹配请求和处理停止匹配请求.
        User user = (User) session.getAttributes().get("user");
        //获取客户端给服务器端发送的数据
        String playLoad = message.getPayload();
        //当前这个数据是一个Json格式的字符串，我们要把它转成Java对象 MatchRequest
        MatchRequest request = objectMapper.readValue(playLoad, MatchRequest.class);
        MatchResponse response = new MatchResponse();
        if (request.getMessage().equals("startMatch")) {
            // 进入匹配队列
            // todo 创建一个类表示匹配队列，把当前用户添加进去
            matcher.add(user);
            // 把玩家放入匹配队列后，就可以将信息返回给客户端了。
            response.setOk(true);
            response.setMessage("startMatch");
        }else if (request.getMessage().equals("stopMatch")) {
            // 退出匹配队列
            // todo 创建一个类表示匹配队列，把当前用户从队列中移除
            matcher.remove(user);
            // 把玩家从匹配队列移除后，就可以返回一个响应给客户端了
            response.setOk(true);
            response.setMessage("stopMatch");
        }else {
            response.setOk(false);
            response.setMessage("非法的匹配请求");
        }
        String jsonString = objectMapper.writeValueAsString(response);
        session.sendMessage(new TextMessage(jsonString));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        try {
            //玩家下线 就要从OnlineUserManager类删除
            User user = (User) session.getAttributes().get("user");
            WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId());
            if (tmpSession == session) {
                onlineUserManager.exitGameHall(user.getUserId());
            }
            //如果玩家正在匹配中，而 websocket连接断开了，就应该移除匹配队列
            matcher.remove(user);
        }catch (NullPointerException e) {
            System.out.println("[MatchAPI.handleTransportError] 当前用户未登录!");
            //e.printStackTrace();
            //出现空指针异常，说明当前用户的身份信息是空的，用户未登录
            //需要把用户未登陆的信息给返回回去
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录，不能进行后续匹配功能！");
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        try {
            //玩家下线 就要从OnlineUserManager类删除
            User user = (User) session.getAttributes().get("user");

            WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId());
            if (tmpSession == session) {
                onlineUserManager.exitGameHall(user.getUserId());
            }
            //如果玩家正在匹配中，而 websocket连接断开了，就应该移除匹配队列
            matcher.remove(user);

        }catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionClosed] 当前用户未登录!");
            //e.printStackTrace();
            //出现空指针异常，说明当前用户的身份信息是空的，用户未登录
            //需要把用户未登陆的信息给返回回去
            //这段代码之前写的草率了
            //不应该在连接关闭之后, 还尝试发送消息给客户端
//            MatchResponse response = new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录，不能进行后续匹配功能！");
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }
}
